// @flow

import config from '../config';
import {warn} from './debug';


// - handle error (错误处理)
export function handleError(err: Error, vm: any, info: string) {
    if(vm) {
        let cur = vm;
        while((cur = cur.$parent)) {
            const hooks = cur.$options.errorCaptured;
            if (hooks) {
                for (let i = 0; i < hooks.length; i++) {
                    try {
                        const capture = hooks[i].call(cur, err, vm, info) === false;
                        if (capture) return;
                    } catch (e) {
                        globalHandleError(e, cur, 'errorCaptured hook')
                    }
                }
            }
        }
    }
    globalHandleError(err, vm, info);
};


// - invoked with error handling (调用错误处理)
export function invokeWithErrorHandling (
    handler: Function,
    context: any,
    args: null | any[],
    vm: any,
    info: string
) {
    let res;
    try {
        res = args ? handler.apply(context, args): handler.call(context);
        if (isPromise(res)) {
            res.catch(e => handleError(e, vm, info + `(Promise/async)`))
        } catch (e) {
            handleError(e, vm, info);
        }
    }
    return res;
};

// - global handle error 全局错误处理
function globalHandleError(err, vm, info) {
    if (config.errorHandler) {
        try {
            return config.errorHandler.call(null, err, vm, info);
        } catch (e) {
            logError(e, null, 'config.errorHandler');
        }
    }
    logError(err, vm, info);
};

function logError(err, vm, info) {
    if (process.env.NODE_ENV !== 'production') {
        warn(`Error in ${info}: "${err.toString()}"`, vm);
    }
    /* istanbul ignore else */
    if ((inBrowser || inWeex) && typeof console !== 'undefined') {
        console.error(err);
    } else {
        throw err;
    }
}